Upstream dom/ tests from jsdom
diff --git a/dom/attributes-are-nodes.html b/dom/attributes-are-nodes.html new file mode 100644 index 0000000..54ff4cc --- /dev/null +++ b/dom/attributes-are-nodes.html
@@ -0,0 +1,55 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Attributes are Nodes but should not be accepted outside of the `attributes` NamedNodeMap</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-core-changes"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + + const attribute = document.createAttribute("newattribute"); + + assert_true(attribute instanceof Node, "attribute instances are instances of Node"); + assert_true(Attr.prototype instanceof Node, "attribute instances are instances of Node"); + +}, "Attrs are subclasses of Nodes"); + +test(() => { + + const parent = document.createElement("p"); + + const attribute = document.createAttribute("newattribute"); + assert_throws_dom("HierarchyRequestError", () => { + parent.appendChild(attribute); + }); + +}, "appendChild with an attribute as the child should fail"); + +test(() => { + + const parent = document.createElement("p"); + parent.appendChild(document.createElement("span")); + + const attribute = document.createAttribute("newattribute"); + assert_throws_dom("HierarchyRequestError", () => { + parent.replaceChild(attribute, parent.firstChild); + }); + +}, "replaceChild with an attribute as the child should fail"); + +test(() => { + + const parent = document.createElement("p"); + parent.appendChild(document.createElement("span")); + + const attribute = document.createAttribute("newattribute"); + assert_throws_dom("HierarchyRequestError", () => { + parent.insertBefore(attribute, parent.firstChild); + }); + +}, "insertBefore with an attribute as the child should fail"); + +</script> diff --git a/dom/collections/HTMLCollection-iterator.html b/dom/collections/HTMLCollection-iterator.html new file mode 100644 index 0000000..4a3f630 --- /dev/null +++ b/dom/collections/HTMLCollection-iterator.html
@@ -0,0 +1,45 @@ +<!doctype html> +<meta charset="utf-8"> +<link rel="help" href="https://dom.spec.whatwg.org/#interface-htmlcollection"> +<link rel="help" href="https://heycam.github.io/webidl/#es-iterator"> +<title>HTMLCollection @@iterator Test</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<p id="1"></p> +<p id="2"></p> +<p id="3"></p> +<p id="4"></p> +<p id="5"></p> +<script> +"use strict"; + +const paragraphs = document.getElementsByTagName("p"); + +test(() => { + assert_true("length" in paragraphs); +}, "HTMLCollection has length method."); + +test(() => { + assert_false("values" in paragraphs); +}, "HTMLCollection does not have iterable's values method."); + +test(() => { + assert_false("entries" in paragraphs); +}, "HTMLCollection does not have iterable's entries method."); + +test(() => { + assert_false("forEach" in paragraphs); +}, "HTMLCollection does not have iterable's forEach method."); + +test(() => { + assert_true(Symbol.iterator in paragraphs); +}, "HTMLCollection has Symbol.iterator."); + +test(() => { + const ids = "12345"; + let idx = 0; + for (const element of paragraphs) { + assert_equals(element.getAttribute("id"), ids[idx++]); + } +}, "HTMLCollection is iterable via for-of loop."); +</script> diff --git a/dom/events/Event-stopImmediatePropagation.html b/dom/events/Event-stopImmediatePropagation.html new file mode 100644 index 0000000..b757322 --- /dev/null +++ b/dom/events/Event-stopImmediatePropagation.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Event's stopImmediatePropagation</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-event-stopimmediatepropagation"> +<link rel="author" href="mailto:d@domenic.me" title="Domenic Denicola"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div id="target"></div> + +<script> +"use strict"; + +setup({ single_test: true }); + +const target = document.querySelector("#target"); + +let timesCalled = 0; +target.addEventListener("test", e => { + ++timesCalled; + e.stopImmediatePropagation(); + assert_equals(e.cancelBubble, true, "The stop propagation flag must have been set"); +}); +target.addEventListener("test", () => { + ++timesCalled; +}); + +const e = new Event("test"); +target.dispatchEvent(e); +assert_equals(timesCalled, 1, "The second listener must not have been called"); + +done(); +</script> diff --git a/dom/events/EventTarget-add-listener-platform-object.html b/dom/events/EventTarget-add-listener-platform-object.html new file mode 100644 index 0000000..d5565c2 --- /dev/null +++ b/dom/events/EventTarget-add-listener-platform-object.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>addEventListener with a platform object</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +</script> +<my-custom-click id=click>Click me!</my-custom-click> +<script> +"use strict"; +setup({ single_test: true }); + +class MyCustomClick extends HTMLElement { + connectedCallback() { + this.addEventListener("click", this); + } + + handleEvent(event) { + if (event.target === this) { + this.dataset.yay = "It worked!"; + } + } +} +window.customElements.define("my-custom-click", MyCustomClick); + +const customElement = document.getElementById("click"); +customElement.click(); + +assert_equals(customElement.dataset.yay, "It worked!"); + +done(); +</script> diff --git a/dom/events/EventTarget-add-remove-listener.html b/dom/events/EventTarget-add-remove-listener.html new file mode 100644 index 0000000..8fb9f43 --- /dev/null +++ b/dom/events/EventTarget-add-remove-listener.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>EventTarget's addEventListener + removeEventListener</title> +<link rel="author" title="Sebastian Mayr" href="mailto:wpt@smayr.name"> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener"> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-eventtarget-removeeventlistener"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +"use strict"; + +function listener(evt) { + evt.preventDefault(); + return false; +} + +test(() => { + document.addEventListener("x", listener, false); + let event = new Event("x", { cancelable: true }); + let ret = document.dispatchEvent(event); + assert_false(ret); + + document.removeEventListener("x", listener); + event = new Event("x", { cancelable: true }); + ret = document.dispatchEvent(event); + assert_true(ret); +}, "Removing an event listener without explicit capture arg should succeed"); +</script> diff --git a/dom/events/EventTarget-this-of-listener.html b/dom/events/EventTarget-this-of-listener.html new file mode 100644 index 0000000..506564c --- /dev/null +++ b/dom/events/EventTarget-this-of-listener.html
@@ -0,0 +1,182 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>EventTarget listeners this value</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-event-listener-invoke"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + + const nodes = [ + document.createElement("p"), + document.createTextNode("some text"), + document.createDocumentFragment(), + document.createComment("a comment"), + document.createProcessingInstruction("target", "data") + ]; + + let callCount = 0; + for (const node of nodes) { + node.addEventListener("someevent", function () { + ++callCount; + assert_equals(this, node); + }); + + node.dispatchEvent(new CustomEvent("someevent")); + } + + assert_equals(callCount, nodes.length); + +}, "the this value inside the event listener callback should be the node"); + +test(() => { + + const nodes = [ + document.createElement("p"), + document.createTextNode("some text"), + document.createDocumentFragment(), + document.createComment("a comment"), + document.createProcessingInstruction("target", "data") + ]; + + let callCount = 0; + for (const node of nodes) { + const handler = { + handleEvent() { + ++callCount; + assert_equals(this, handler); + } + }; + + node.addEventListener("someevent", handler); + + node.dispatchEvent(new CustomEvent("someevent")); + } + + assert_equals(callCount, nodes.length); + +}, "the this value inside the event listener object handleEvent should be the object"); + +test(() => { + + const nodes = [ + document.createElement("p"), + document.createTextNode("some text"), + document.createDocumentFragment(), + document.createComment("a comment"), + document.createProcessingInstruction("target", "data") + ]; + + let callCount = 0; + for (const node of nodes) { + const handler = { + handleEvent() { + assert_unreached("should not call the old handleEvent method"); + } + }; + + node.addEventListener("someevent", handler); + handler.handleEvent = function () { + ++callCount; + assert_equals(this, handler); + }; + + node.dispatchEvent(new CustomEvent("someevent")); + } + + assert_equals(callCount, nodes.length); + +}, "dispatchEvent should invoke the current handleEvent method of the object"); + +test(() => { + + const nodes = [ + document.createElement("p"), + document.createTextNode("some text"), + document.createDocumentFragment(), + document.createComment("a comment"), + document.createProcessingInstruction("target", "data") + ]; + + let callCount = 0; + for (const node of nodes) { + const handler = {}; + + node.addEventListener("someevent", handler); + handler.handleEvent = function () { + ++callCount; + assert_equals(this, handler); + }; + + node.dispatchEvent(new CustomEvent("someevent")); + } + + assert_equals(callCount, nodes.length); + +}, "addEventListener should not require handleEvent to be defined on object listeners"); + +test(() => { + + const nodes = [ + document.createElement("p"), + document.createTextNode("some text"), + document.createDocumentFragment(), + document.createComment("a comment"), + document.createProcessingInstruction("target", "data") + ]; + + let callCount = 0; + for (const node of nodes) { + function handler() { + ++callCount; + assert_equals(this, node); + } + + handler.handleEvent = () => { + assert_unreached("should not call the handleEvent method on a function"); + }; + + node.addEventListener("someevent", handler); + + node.dispatchEvent(new CustomEvent("someevent")); + } + + assert_equals(callCount, nodes.length); + +}, "handleEvent properties added to a function before addEventListener are not reached"); + +test(() => { + + const nodes = [ + document.createElement("p"), + document.createTextNode("some text"), + document.createDocumentFragment(), + document.createComment("a comment"), + document.createProcessingInstruction("target", "data") + ]; + + let callCount = 0; + for (const node of nodes) { + function handler() { + ++callCount; + assert_equals(this, node); + } + + node.addEventListener("someevent", handler); + + handler.handleEvent = () => { + assert_unreached("should not call the handleEvent method on a function"); + }; + + node.dispatchEvent(new CustomEvent("someevent")); + } + + assert_equals(callCount, nodes.length); + +}, "handleEvent properties added to a function after addEventListener are not reached"); + +</script> diff --git a/dom/nodes/Document-createCDATASection.html b/dom/nodes/Document-createCDATASection.html new file mode 100644 index 0000000..72b3684 --- /dev/null +++ b/dom/nodes/Document-createCDATASection.html
@@ -0,0 +1,16 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>document.createCDATASection must throw in HTML documents</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-document-createcdatasection"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +setup({ single_test: true }); + +assert_throws_dom("NotSupportedError", () => document.createCDATASection("foo")); + +done(); +</script> diff --git a/dom/nodes/Document-createCDATASection.xhtml b/dom/nodes/Document-createCDATASection.xhtml new file mode 100644 index 0000000..b0a5a7f --- /dev/null +++ b/dom/nodes/Document-createCDATASection.xhtml
@@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <meta charset="utf-8"/> + <title>document.createCDATASection</title> + <link rel="help" href="https://dom.spec.whatwg.org/#dom-document-createcdatasection"/> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="Document-createComment-createTextNode.js"></script> +</head> + +<body> + <script> + "use strict"; + test_create("createCDATASection", CDATASection, 4, "#cdata-section"); + + test(() => { + assert_throws_dom("InvalidCharacterError", () => document.createCDATASection(" ]" + "]> ")); + }, "Creating a CDATA section containing the string \"]" + "]>\" must throw"); + </script> +</body> +</html> diff --git a/dom/nodes/DocumentFragment-constructor.html b/dom/nodes/DocumentFragment-constructor.html new file mode 100644 index 0000000..e97a7c4 --- /dev/null +++ b/dom/nodes/DocumentFragment-constructor.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>DocumentFragment constructor</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-documentfragment-documentfragment"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + const fragment = new DocumentFragment(); + assert_equals(fragment.ownerDocument, document); +}, "Sets the owner document to the current global object associated document"); + +test(() => { + const fragment = new DocumentFragment(); + const text = document.createTextNode(""); + fragment.appendChild(text); + assert_equals(fragment.firstChild, text); +}, "Create a valid document DocumentFragment"); +</script> diff --git a/dom/nodes/DocumentFragment-getElementById.html b/dom/nodes/DocumentFragment-getElementById.html new file mode 100644 index 0000000..ce0d302 --- /dev/null +++ b/dom/nodes/DocumentFragment-getElementById.html
@@ -0,0 +1,62 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>DocumentFragment.prototype.getElementById</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-nonelementparentnode-getelementbyid"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<template> + <div id="bar"> + <span id="foo" data-yes></span> + </div> + <div id="foo"> + <span id="foo"></span> + <ul id="bar"> + <li id="foo"></li> + </ul> + </div> +</template> + +<script> +"use strict"; + +test(() => { + assert_equals(typeof DocumentFragment.prototype.getElementById, "function", "It must exist on the prototype"); + assert_equals(typeof document.createDocumentFragment().getElementById, "function", "It must exist on an instance"); +}, "The method must exist"); + +test(() => { + assert_equals(document.createDocumentFragment().getElementById("foo"), null); + assert_equals(document.createDocumentFragment().getElementById(""), null); +}, "It must return null when there are no matches"); + +test(() => { + const frag = document.createDocumentFragment(); + frag.appendChild(document.createElement("div")); + frag.appendChild(document.createElement("span")); + frag.childNodes[0].id = "foo"; + frag.childNodes[1].id = "foo"; + + assert_equals(frag.getElementById("foo"), frag.childNodes[0]); +}, "It must return the first element when there are matches"); + +test(() => { + const frag = document.createDocumentFragment(); + frag.appendChild(document.createElement("div")); + frag.childNodes[0].setAttribute("id", ""); + + assert_equals( + frag.getElementById(""), + null, + "Even if there is an element with an empty-string ID attribute, it must not be returned" + ); +}, "Empty string ID values"); + +test(() => { + const frag = document.querySelector("template").content; + + assert_true(frag.getElementById("foo").hasAttribute("data-yes")); +}, "It must return the first element when there are matches, using a template"); +</script> diff --git a/dom/nodes/DocumentFragment-querySelectorAll-after-modification.html b/dom/nodes/DocumentFragment-querySelectorAll-after-modification.html new file mode 100644 index 0000000..8049363 --- /dev/null +++ b/dom/nodes/DocumentFragment-querySelectorAll-after-modification.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelectorAll should still work on DocumentFragments after they are modified</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2290 --> + +<script> +"use strict"; + +setup({ single_test: true }); + +const frag = document.createDocumentFragment(); +frag.appendChild(document.createElement("div")); + +assert_array_equals(frag.querySelectorAll("img"), [], "before modification"); + +frag.appendChild(document.createElement("div")); + +// If the bug is present, this will throw. +assert_array_equals(frag.querySelectorAll("img"), [], "after modification"); + +done(); +</script> diff --git a/dom/nodes/Element-hasAttribute.html b/dom/nodes/Element-hasAttribute.html new file mode 100644 index 0000000..26528d7 --- /dev/null +++ b/dom/nodes/Element-hasAttribute.html
@@ -0,0 +1,32 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Element.prototype.hasAttribute</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-hasattribute"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<span data-e2="2" data-F2="3" id="t"></span> + +<script> +"use strict"; + +test(() => { + + const el = document.createElement("p"); + el.setAttributeNS("foo", "x", "first"); + + assert_true(el.hasAttribute("x")); + +}, "hasAttribute should check for attribute presence, irrespective of namespace"); + +test(() => { + + const el = document.getElementById("t"); + + assert_true(el.hasAttribute("data-e2")); + assert_true(el.hasAttribute("data-E2")); + assert_true(el.hasAttribute("data-f2")); + assert_true(el.hasAttribute("data-F2")); + +}, "hasAttribute should work with all attribute casings"); +</script> diff --git a/dom/nodes/Element-matches-namespaced-elements.html b/dom/nodes/Element-matches-namespaced-elements.html new file mode 100644 index 0000000..e61b11c --- /dev/null +++ b/dom/nodes/Element-matches-namespaced-elements.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>matches/webkitMatchesSelector must work when an element has a namespace</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression tests for https://github.com/jsdom/jsdom/issues/1846, https://github.com/jsdom/jsdom/issues/2247 --> + +<script> +"use strict"; + +for (const method of ["matches", "webkitMatchesSelector"]) { + test(() => { + assert_true(document.createElementNS("", "element")[method]("element")); + }, `empty string namespace, ${method}`); + + test(() => { + assert_true(document.createElementNS("urn:ns", "h")[method]("h")); + }, `has a namespace, ${method}`); + + test(() => { + assert_true(document.createElementNS("urn:ns", "h")[method]("*|h")); + }, `has a namespace, *|, ${method}`); +} +</script> diff --git a/dom/nodes/Element-removeAttribute.html b/dom/nodes/Element-removeAttribute.html new file mode 100644 index 0000000..df79e62 --- /dev/null +++ b/dom/nodes/Element-removeAttribute.html
@@ -0,0 +1,58 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Element.prototype.removeAttribute</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-removeattribute"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + + const el = document.createElement("p"); + el.setAttribute("x", "first"); + el.setAttributeNS("foo", "x", "second"); + + assert_equals(el.attributes.length, 2); + assert_equals(el.getAttribute("x"), "first"); + assert_equals(el.getAttributeNS(null, "x"), "first"); + assert_equals(el.getAttributeNS("foo", "x"), "second"); + + // removeAttribute removes the first attribute with name "x" that + // we set on the element, irrespective of namespace. + el.removeAttribute("x"); + + // The only attribute remaining should be the second one. + assert_equals(el.getAttribute("x"), "second"); + assert_equals(el.getAttributeNS(null, "x"), null); + assert_equals(el.getAttributeNS("foo", "x"), "second"); + assert_equals(el.attributes.length, 1, "one attribute"); + +}, "removeAttribute should remove the first attribute, irrespective of namespace, when the first attribute is " + + "not in a namespace"); + +test(() => { + + const el = document.createElement("p"); + el.setAttributeNS("foo", "x", "first"); + el.setAttributeNS("foo2", "x", "second"); + + assert_equals(el.attributes.length, 2); + assert_equals(el.getAttribute("x"), "first"); + assert_equals(el.getAttributeNS("foo", "x"), "first"); + assert_equals(el.getAttributeNS("foo2", "x"), "second"); + + // removeAttribute removes the first attribute with name "x" that + // we set on the element, irrespective of namespace. + el.removeAttribute("x"); + + // The only attribute remaining should be the second one. + assert_equals(el.getAttribute("x"), "second"); + assert_equals(el.getAttributeNS("foo", "x"), null); + assert_equals(el.getAttributeNS("foo2", "x"), "second"); + assert_equals(el.attributes.length, 1, "one attribute"); + +}, "removeAttribute should remove the first attribute, irrespective of namespace, when the first attribute is " + + "in a namespace"); +</script> diff --git a/dom/nodes/Element-setAttribute.html b/dom/nodes/Element-setAttribute.html new file mode 100644 index 0000000..7609406 --- /dev/null +++ b/dom/nodes/Element-setAttribute.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Element.prototype.setAttribute</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-element-setattribute"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + + const el = document.createElement("p"); + el.setAttributeNS("foo", "x", "first"); + el.setAttributeNS("foo2", "x", "second"); + + el.setAttribute("x", "changed"); + + assert_equals(el.attributes.length, 2); + assert_equals(el.getAttribute("x"), "changed"); + assert_equals(el.getAttributeNS("foo", "x"), "changed"); + assert_equals(el.getAttributeNS("foo2", "x"), "second"); + +}, "setAttribute should change the first attribute, irrespective of namespace"); + +test(() => { + // https://github.com/whatwg/dom/issues/31 + + const el = document.createElement("p"); + el.setAttribute("FOO", "bar"); + + assert_equals(el.getAttribute("foo"), "bar"); + assert_equals(el.getAttribute("FOO"), "bar"); + assert_equals(el.getAttributeNS("", "foo"), "bar"); + assert_equals(el.getAttributeNS("", "FOO"), null); + +}, "setAttribute should lowercase before setting"); +</script> diff --git a/dom/nodes/Element-tagName.html b/dom/nodes/Element-tagName.html index 035a23c..43e7a2d 100644 --- a/dom/nodes/Element-tagName.html +++ b/dom/nodes/Element-tagName.html
@@ -17,8 +17,15 @@ assert_equals(document.createElementNS(SVGNS, "SVG").tagName, "SVG") assert_equals(document.createElementNS(SVGNS, "s:svg").tagName, "s:svg") assert_equals(document.createElementNS(SVGNS, "s:SVG").tagName, "s:SVG") + + assert_equals(document.createElementNS(SVGNS, "textPath").tagName, "textPath"); }, "tagName should not upper-case for SVG elements in HTML documents.") +test(() => { + const el2 = document.createElementNS("http://example.com/", "mixedCase"); + assert_equals(el2.tagName, "mixedCase"); +}, "tagName should not upper-case for other non-HTML namespaces"); + test(function() { if ("DOMParser" in window) { var xmlel = new DOMParser() diff --git a/dom/nodes/Node-cloneNode-XMLDocument.html b/dom/nodes/Node-cloneNode-XMLDocument.html new file mode 100644 index 0000000..2c63c77 --- /dev/null +++ b/dom/nodes/Node-cloneNode-XMLDocument.html
@@ -0,0 +1,28 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Cloning of an XMLDocument</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-node-clonenode"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-node-clone"> + +<!-- This is testing in particular "that implements the same interfaces as node" --> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + const doc = document.implementation.createDocument("namespace", ""); + + assert_equals( + doc.constructor, XMLDocument, + "Precondition check: document.implementation.createDocument() creates an XMLDocument" + ); + + const clone = doc.cloneNode(true); + + assert_equals(clone.constructor, XMLDocument); +}, "Created with createDocument"); + +</script> diff --git a/dom/nodes/Node-cloneNode-document-with-doctype.html b/dom/nodes/Node-cloneNode-document-with-doctype.html new file mode 100644 index 0000000..2196308 --- /dev/null +++ b/dom/nodes/Node-cloneNode-document-with-doctype.html
@@ -0,0 +1,51 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Cloning of a document with a doctype</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-node-clonenode"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-node-clone"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + const doctype = document.implementation.createDocumentType("name", "publicId", "systemId"); + const doc = document.implementation.createDocument("namespace", "", doctype); + + const clone = doc.cloneNode(true); + + assert_equals(clone.childNodes.length, 1, "Only one child node"); + assert_equals(clone.childNodes[0].nodeType, Node.DOCUMENT_TYPE_NODE, "Is a document fragment"); + assert_equals(clone.childNodes[0].name, "name"); + assert_equals(clone.childNodes[0].publicId, "publicId"); + assert_equals(clone.childNodes[0].systemId, "systemId"); +}, "Created with the createDocument/createDocumentType"); + +test(() => { + const doc = document.implementation.createHTMLDocument(); + + const clone = doc.cloneNode(true); + + assert_equals(clone.childNodes.length, 2, "Two child nodes"); + assert_equals(clone.childNodes[0].nodeType, Node.DOCUMENT_TYPE_NODE, "Is a document fragment"); + assert_equals(clone.childNodes[0].name, "html"); + assert_equals(clone.childNodes[0].publicId, ""); + assert_equals(clone.childNodes[0].systemId, ""); +}, "Created with the createHTMLDocument"); + +test(() => { + const parser = new window.DOMParser(); + const doc = parser.parseFromString("<!DOCTYPE html><html></html>", "text/html"); + + const clone = doc.cloneNode(true); + + assert_equals(clone.childNodes.length, 2, "Two child nodes"); + assert_equals(clone.childNodes[0].nodeType, Node.DOCUMENT_TYPE_NODE, "Is a document fragment"); + assert_equals(clone.childNodes[0].name, "html"); + assert_equals(clone.childNodes[0].publicId, ""); + assert_equals(clone.childNodes[0].systemId, ""); +}, "Created with DOMParser"); + +</script> diff --git a/dom/nodes/Node-cloneNode-external-stylesheet-no-bc.sub.html b/dom/nodes/Node-cloneNode-external-stylesheet-no-bc.sub.html new file mode 100644 index 0000000..bce6074 --- /dev/null +++ b/dom/nodes/Node-cloneNode-external-stylesheet-no-bc.sub.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>cloneNode on a stylesheet link in a browsing-context-less document</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2497 --> + +<script> +"use strict"; + +setup({ single_test: true }); + +const doc = document.implementation.createHTMLDocument(); + +// Bug was only triggered by absolute URLs, for some reason... +const absoluteURL = new URL("/common/canvas-frame.css", location.href); +doc.head.innerHTML = `<link rel="stylesheet" href="${absoluteURL}">`; + +// Test passes if this does not throw/crash +doc.cloneNode(true); + +done(); +</script> diff --git a/dom/nodes/Node-cloneNode-svg.html b/dom/nodes/Node-cloneNode-svg.html new file mode 100644 index 0000000..9d4704b --- /dev/null +++ b/dom/nodes/Node-cloneNode-svg.html
@@ -0,0 +1,63 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Cloning of SVG elements and attributes</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-node-clonenode"> +<link rel="help" href="https://dom.spec.whatwg.org/#concept-node-clone"> +<!-- regression test for https://github.com/jsdom/jsdom/issues/1601 --> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<svg xmlns:xlink='http://www.w3.org/1999/xlink'><use xlink:href='#test'></use></svg> + +<script> +"use strict"; + +const svg = document.querySelector("svg"); +const clone = svg.cloneNode(true); + +test(() => { + + assert_equals(clone.namespaceURI, "http://www.w3.org/2000/svg"); + assert_equals(clone.prefix, null); + assert_equals(clone.localName, "svg"); + assert_equals(clone.tagName, "svg"); + +}, "cloned <svg> should have the right properties"); + +test(() => { + + const attr = clone.attributes[0]; + + assert_equals(attr.namespaceURI, "http://www.w3.org/2000/xmlns/"); + assert_equals(attr.prefix, "xmlns"); + assert_equals(attr.localName, "xlink"); + assert_equals(attr.name, "xmlns:xlink"); + assert_equals(attr.value, "http://www.w3.org/1999/xlink"); + +}, "cloned <svg>'s xmlns:xlink attribute should have the right properties"); + +test(() => { + + const use = clone.firstElementChild; + assert_equals(use.namespaceURI, "http://www.w3.org/2000/svg"); + assert_equals(use.prefix, null); + assert_equals(use.localName, "use"); + assert_equals(use.tagName, "use"); + +}, "cloned <use> should have the right properties"); + +test(() => { + + const use = clone.firstElementChild; + const attr = use.attributes[0]; + + assert_equals(attr.namespaceURI, "http://www.w3.org/1999/xlink"); + assert_equals(attr.prefix, "xlink"); + assert_equals(attr.localName, "href"); + assert_equals(attr.name, "xlink:href"); + assert_equals(attr.value, "#test"); + +}, "cloned <use>'s xlink:href attribute should have the right properties"); + +</script> diff --git a/dom/nodes/Node-isConnected-shadow-dom.html b/dom/nodes/Node-isConnected-shadow-dom.html new file mode 100644 index 0000000..7d04dc3 --- /dev/null +++ b/dom/nodes/Node-isConnected-shadow-dom.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Test of Node.isConnected in a shadow tree</title> +<link rel="help" href="https://dom.spec.whatwg.org/#connected"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +"use strict"; + +function testIsConnected(mode) { + test(() => { + const host = document.createElement("div"); + document.body.appendChild(host); + + const root = host.attachShadow({ mode }); + + const node = document.createElement("div"); + root.appendChild(node); + + assert_true(node.isConnected); + }, `Node.isConnected in a ${mode} shadow tree`); +} + +for (const mode of ["closed", "open"]) { + testIsConnected(mode); +} +</script> diff --git a/dom/nodes/Node-mutation-adoptNode.html b/dom/nodes/Node-mutation-adoptNode.html new file mode 100644 index 0000000..9c9594c --- /dev/null +++ b/dom/nodes/Node-mutation-adoptNode.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Node-manipulation-adopted</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-domimplementation-createhtmldocument"> +<link rel=help href="https://dom.spec.whatwg.org/#mutation-algorithms"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +"use strict"; + +test(() => { + const old = document.implementation.createHTMLDocument(""); + const div = old.createElement("div"); + div.appendChild(old.createTextNode("text")); + assert_equals(div.ownerDocument, old); + assert_equals(div.firstChild.ownerDocument, old); + document.body.appendChild(div); + assert_equals(div.ownerDocument, document); + assert_equals(div.firstChild.ownerDocument, document); +}, "simple append of foreign div with text"); + +</script> diff --git a/dom/nodes/ParentNode-querySelector-case-insensitive.html b/dom/nodes/ParentNode-querySelector-case-insensitive.html new file mode 100644 index 0000000..e461ee5 --- /dev/null +++ b/dom/nodes/ParentNode-querySelector-case-insensitive.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelector(All) must work with the i and *= selectors</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2551 --> + +<input name="User" id="testInput"></input> + +<script> +"use strict"; +const input = document.getElementById("testInput"); + +test(() => { + assert_equals(document.querySelector("input[name*=user i]"), input); +}, "querySelector"); + +test(() => { + assert_array_equals(document.querySelectorAll("input[name*=user i]"), [input]); +}, "querySelectorAll"); +</script> diff --git a/dom/nodes/ParentNode-querySelector-escapes.html b/dom/nodes/ParentNode-querySelector-escapes.html new file mode 100644 index 0000000..65a75e5 --- /dev/null +++ b/dom/nodes/ParentNode-querySelector-escapes.html
@@ -0,0 +1,123 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>querySelector() with CSS escapes</title> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-parentnode-queryselector"> +<link rel="help" href="https://drafts.csswg.org/css-syntax/#consume-escaped-code-point"> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<link rel="author" title="bellbind" href="mailto:bellbind@gmail.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +function testMatched(id, selector) { + test(() => { + const container = document.createElement("div"); + const child = document.createElement("span"); + child.id = id; + + container.appendChild(child); + + assert_equals(container.querySelector(selector), child); + }, `${JSON.stringify(id)} should match with ${JSON.stringify(selector)}`); +} + +function testNeverMatched(id, selector) { + test(() => { + const container = document.createElement("div"); + const child = document.createElement("span"); + child.id = id; + + container.appendChild(child); + + assert_equals(container.querySelector(selector), null); + }, `${JSON.stringify(id)} should never match with ${JSON.stringify(selector)}`); +} + +// 4.3.7 from https://drafts.csswg.org/css-syntax/#consume-escaped-code-point +testMatched("nonescaped", "#nonescaped"); + +// - escape hex digit +testMatched("0nextIsWhiteSpace", "#\\30 nextIsWhiteSpace"); +testMatched("0nextIsNotHexLetters", "#\\30nextIsNotHexLetters"); +testMatched("0connectHexMoreThan6Hex", "#\\000030connectHexMoreThan6Hex"); +testMatched("0spaceMoreThan6Hex", "#\\000030 spaceMoreThan6Hex"); + +// - hex digit special replacement +// 1. zero points +testMatched("zero\u{fffd}", "#zero\\0"); +testNeverMatched("zero\u{0}", "#zero\\0"); +testMatched("zero\u{fffd}", "#zero\\000000"); +testNeverMatched("zero\u{0}", "#zero\\000000"); +// 2. surrogate points +testMatched("\u{fffd}surrogateFirst", "#\\d83d surrogateFirst"); +testNeverMatched("\ud83dsurrogateFirst", "#\\d83d surrogateFirst"); +testMatched("surrogateSecond\u{fffd}", "#surrogateSecond\\dd11"); +testNeverMatched("surrogateSecond\udd11", "#surrogateSecond\\dd11"); +testMatched("surrogatePair\u{fffd}\u{fffd}", "#surrogatePair\\d83d\\dd11"); +testNeverMatched("surrogatePair\u{1f511}", "#surrogatePair\\d83d\\dd11"); +// 3. out of range points +testMatched("outOfRange\u{fffd}", "#outOfRange\\110000"); +testMatched("outOfRange\u{fffd}", "#outOfRange\\110030"); +testNeverMatched("outOfRange\u{30}", "#outOfRange\\110030"); +testMatched("outOfRange\u{fffd}", "#outOfRange\\555555"); +testMatched("outOfRange\u{fffd}", "#outOfRange\\ffffff"); + +// - escape EOF +testNeverMatched("eof\\", "#eof\\"); + +// - escape anythong else +testMatched(".comma", "#\\.comma"); +testMatched("-minus", "#\\-minus"); +testMatched("g", "#\\g"); + +// non edge cases +testMatched("aBMPRegular", "#\\61 BMPRegular"); +testMatched("\u{1f511}nonBMP", "#\\1f511 nonBMP"); +testMatched("00continueEscapes", "#\\30\\30 continueEscapes"); +testMatched("00continueEscapes", "#\\30 \\30 continueEscapes"); +testMatched("continueEscapes00", "#continueEscapes\\30 \\30 "); +testMatched("continueEscapes00", "#continueEscapes\\30 \\30"); +testMatched("continueEscapes00", "#continueEscapes\\30\\30 "); +testMatched("continueEscapes00", "#continueEscapes\\30\\30"); + +// ident tests case from CSS tests of chromium source: https://goo.gl/3Cxdov +testMatched("hello", "#hel\\6Co"); +testMatched("&B", "#\\26 B"); +testMatched("hello", "#hel\\6C o"); +testMatched("spaces", "#spac\\65\r\ns"); +testMatched("spaces", "#sp\\61\tc\\65\fs"); +testMatched("test\u{D799}", "#test\\D799"); +testMatched("\u{E000}", "#\\E000"); +testMatched("test", "#te\\s\\t"); +testMatched("spaces in\tident", "#spaces\\ in\\\tident"); +testMatched(".,:!", "#\\.\\,\\:\\!"); +testMatched("null\u{fffd}", "#null\\0"); +testMatched("null\u{fffd}", "#null\\0000"); +testMatched("large\u{fffd}", "#large\\110000"); +testMatched("large\u{fffd}", "#large\\23456a"); +testMatched("surrogate\u{fffd}", "#surrogate\\D800"); +testMatched("surrogate\u{fffd}", "#surrogate\\0DBAC"); +testMatched("\u{fffd}surrogate", "#\\00DFFFsurrogate"); +testMatched("\u{10ffff}", "#\\10fFfF"); +testMatched("\u{10ffff}0", "#\\10fFfF0"); +testMatched("\u{100000}00", "#\\10000000"); +testMatched("eof\u{fffd}", "#eof\\"); + +testMatched("simple-ident", "#simple-ident"); +testMatched("testing123", "#testing123"); +testMatched("_underscore", "#_underscore"); +testMatched("-text", "#-text"); +testMatched("-m", "#-\\6d"); +testMatched("--abc", "#--abc"); +testMatched("--", "#--"); +testMatched("--11", "#--11"); +testMatched("---", "#---"); +testMatched("\u{2003}", "#\u{2003}"); +testMatched("\u{A0}", "#\u{A0}"); +testMatched("\u{1234}", "#\u{1234}"); +testMatched("\u{12345}", "#\u{12345}"); +testMatched("\u{fffd}", "#\u{0}"); +testMatched("ab\u{fffd}c", "#ab\u{0}c"); +</script> diff --git a/dom/nodes/ParentNode-querySelector-scope.html b/dom/nodes/ParentNode-querySelector-scope.html new file mode 100644 index 0000000..b08a167 --- /dev/null +++ b/dom/nodes/ParentNode-querySelector-scope.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelector(All) must work with :scope</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2359 --> + +<div><p><span>hello</span></p></div> + +<script> +"use strict"; +const div = document.querySelector("div"); +const p = document.querySelector("p"); + +test(() => { + assert_equals(div.querySelector(":scope > p"), p); + assert_equals(div.querySelector(":scope > span"), null); +}, "querySelector"); + +test(() => { + assert_array_equals(div.querySelectorAll(":scope > p"), [p]); + assert_array_equals(div.querySelectorAll(":scope > span"), []); +}, "querySelectorAll"); +</script> diff --git a/dom/nodes/ParentNode-querySelectorAll-removed-elements.html b/dom/nodes/ParentNode-querySelectorAll-removed-elements.html new file mode 100644 index 0000000..3cefc80 --- /dev/null +++ b/dom/nodes/ParentNode-querySelectorAll-removed-elements.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelectorAll must not return removed elements</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2519 --> + +<div id="container"></div> + +<script> +"use strict"; + +setup({ single_test: true }); + +const container = document.querySelector("#container"); +function getIDs() { + return [...container.querySelectorAll("a.test")].map(el => el.id); +} + +container.innerHTML = `<a id="link-a" class="test">a link</a>`; +assert_array_equals(getIDs(), ["link-a"], "Sanity check: initial setup"); + +container.innerHTML = `<a id="link-b" class="test"><img src="foo.jpg"></a>`; +assert_array_equals(getIDs(), ["link-b"], "After replacement"); + +container.innerHTML = `<a id="link-a" class="test">a link</a>`; +assert_array_equals(getIDs(), ["link-a"], "After changing back to the original HTML"); + +done(); +</script> diff --git a/dom/nodes/ParentNode-querySelectors-exclusive.html b/dom/nodes/ParentNode-querySelectors-exclusive.html new file mode 100644 index 0000000..5cff936 --- /dev/null +++ b/dom/nodes/ParentNode-querySelectors-exclusive.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelector/querySelectorAll should not include their thisArg</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2296 --> + +<script> +"use strict"; + +setup({ single_test: true }); + +const button = document.createElement("button"); + +assert_equals(button.querySelector("*"), null, "querySelector, '*', before modification"); +assert_equals(button.querySelector("button"), null, "querySelector, 'button', before modification"); +assert_equals(button.querySelector("button, span"), null, "querySelector, 'button, span', before modification"); +assert_array_equals(button.querySelectorAll("*"), [], "querySelectorAll, '*', before modification"); +assert_array_equals(button.querySelectorAll("button"), [], "querySelectorAll, 'button', before modification"); +assert_array_equals( + button.querySelectorAll("button, span"), [], + "querySelectorAll, 'button, span', before modification" +); + + +button.innerHTML = "text"; + +assert_equals(button.querySelector("*"), null, "querySelector, '*', after modification"); +assert_equals(button.querySelector("button"), null, "querySelector, 'button', after modification"); +assert_equals(button.querySelector("button, span"), null, "querySelector, 'button, span', after modification"); +assert_array_equals(button.querySelectorAll("*"), [], "querySelectorAll, '*', after modification"); +assert_array_equals(button.querySelectorAll("button"), [], "querySelectorAll, 'button', after modification"); +assert_array_equals( + button.querySelectorAll("button, span"), [], + "querySelectorAll, 'button, span', after modification" +); + +done(); +</script> diff --git a/dom/nodes/ParentNode-querySelectors-namespaces.html b/dom/nodes/ParentNode-querySelectors-namespaces.html new file mode 100644 index 0000000..714999b --- /dev/null +++ b/dom/nodes/ParentNode-querySelectors-namespaces.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelectorAll must work with namespace attribute selectors on SVG</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2028 --> + +<svg id="thesvg" xlink:href="foo"></svg> + +<script> +"use strict"; + +setup({ single_test: true }); + +const el = document.getElementById("thesvg"); + +assert_equals(document.querySelector("[*|href]"), el); +assert_array_equals(document.querySelectorAll("[*|href]"), [el]); + +done(); +</script> diff --git a/dom/nodes/ParentNode-querySelectors-space-and-dash-attribute-value.html b/dom/nodes/ParentNode-querySelectors-space-and-dash-attribute-value.html new file mode 100644 index 0000000..e08c6e6 --- /dev/null +++ b/dom/nodes/ParentNode-querySelectors-space-and-dash-attribute-value.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelector(All) must work for attribute values that contain spaces and dashes</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<!-- Regression test for https://github.com/jsdom/jsdom/issues/2542 --> + +<a title="test with - dash and space" id="testme">Test One</a> + +<script> +"use strict"; +const el = document.getElementById("testme"); + +test(() => { + assert_equals(document.querySelector("a[title='test with - dash and space']"), el); +}, "querySelector"); + +test(() => { + assert_equals(document.querySelector("a[title='test with - dash and space']"), el); +}, "querySelectorAll"); +</script> diff --git a/dom/nodes/Text-wholeText.html b/dom/nodes/Text-wholeText.html new file mode 100644 index 0000000..2467930 --- /dev/null +++ b/dom/nodes/Text-wholeText.html
@@ -0,0 +1,46 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Text - wholeText</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-text-wholetext"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script> +"use strict"; + +test(() => { + const parent = document.createElement("div"); + + const t1 = document.createTextNode("a"); + const t2 = document.createTextNode("b"); + const t3 = document.createTextNode("c"); + + assert_equals(t1.wholeText, t1.textContent); + + parent.appendChild(t1); + + assert_equals(t1.wholeText, t1.textContent); + + parent.appendChild(t2); + + assert_equals(t1.wholeText, t1.textContent + t2.textContent); + assert_equals(t2.wholeText, t1.textContent + t2.textContent); + + parent.appendChild(t3); + + assert_equals(t1.wholeText, t1.textContent + t2.textContent + t3.textContent); + assert_equals(t2.wholeText, t1.textContent + t2.textContent + t3.textContent); + assert_equals(t3.wholeText, t1.textContent + t2.textContent + t3.textContent); + + const a = document.createElement("a"); + a.textContent = "I'm an Anchor"; + parent.insertBefore(a, t3); + + const span = document.createElement("span"); + span.textContent = "I'm a Span"; + parent.appendChild(document.createElement("span")); + + assert_equals(t1.wholeText, t1.textContent + t2.textContent); + assert_equals(t2.wholeText, t1.textContent + t2.textContent); + assert_equals(t3.wholeText, t3.textContent); +}, "wholeText returns text of all Text nodes logically adjacent to the node, in document order."); +</script> diff --git a/dom/nodes/attributes-namednodemap.html b/dom/nodes/attributes-namednodemap.html new file mode 100644 index 0000000..96f9d30 --- /dev/null +++ b/dom/nodes/attributes-namednodemap.html
@@ -0,0 +1,120 @@ +<!DOCTYPE HTML> +<title>Tests of some tricky semantics around NamedNodeMap and the element.attributes collection</title> +<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me"> +<link rel="help" href="https://dom.spec.whatwg.org/#interface-namednodemap"> +<link rel="help" href="https://dom.spec.whatwg.org/#dom-element-attributes"> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +"use strict"; + +test(() => { + + const element = document.createElement("div"); + element.setAttribute("x", "first"); + + assert_equals(element.attributes.length, 1, "one attribute"); + assert_equals(element.attributes.x.value, "first"); + +}, "an attribute set by setAttribute should be accessible as a field on the `attributes` field of an Element"); + +test(() => { + + const element = document.createElement("div"); + const map = element.attributes; + + assert_equals(map.length, 0); + + const attr1 = document.createAttribute("attr1"); + map.setNamedItem(attr1); + assert_equals(map.attr1, attr1); + assert_equals(map.length, 1); + + const attr2 = document.createAttribute("attr2"); + map.setNamedItem(attr2); + assert_equals(map.attr2, attr2); + assert_equals(map.length, 2); + + const rm1 = map.removeNamedItem("attr1"); + assert_equals(rm1, attr1); + assert_equals(map.length, 1); + + const rm2 = map.removeNamedItem("attr2"); + assert_equals(rm2, attr2); + assert_equals(map.length, 0); + +}, "setNamedItem and removeNamedItem on `attributes` should add and remove fields from `attributes`"); + +test(() => { + + const element = document.createElement("div"); + const map = element.attributes; + + const fooAttribute = document.createAttribute("foo"); + map.setNamedItem(fooAttribute); + + const itemAttribute = document.createAttribute("item"); + map.setNamedItem(itemAttribute); + + assert_equals(map.foo, fooAttribute); + assert_equals(map.item, NamedNodeMap.prototype.item); + assert_equals(typeof map.item, "function"); + + map.removeNamedItem("item"); + assert_equals(map.item, NamedNodeMap.prototype.item); + assert_equals(typeof map.item, "function"); + +}, "setNamedItem and removeNamedItem on `attributes` should not interfere with existing method names"); + +test(() => { + + const element = document.createElement("div"); + element.setAttributeNS(null, "x", "first"); + + assert_equals(element.attributes.length, 1, "one attribute"); + assert_equals(element.attributes.x.value, "first"); + +}, "an attribute with a null namespace should be accessible as a field on the `attributes` field of an Element"); + +test(() => { + + const element = document.createElement("div"); + element.setAttributeNS("foo", "x", "first"); + + assert_equals(element.attributes.length, 1, "one attribute"); + assert_equals(element.attributes.x.value, "first"); + +}, "an attribute with a set namespace should be accessible as a field on the `attributes` field of an Element"); + +test(() => { + + const element = document.createElement("div"); + element.setAttributeNS("foo", "setNamedItem", "first"); + + assert_equals(element.attributes.length, 1, "one attribute"); + assert_equals(typeof element.attributes.setNamedItem, "function"); + +}, "setting an attribute should not overwrite the methods of an `NamedNodeMap` object"); + +test(() => { + + const element = document.createElement("div"); + element.setAttributeNS("foo", "toString", "first"); + + assert_equals(element.attributes.length, 1, "one attribute"); + assert_equals(typeof element.attributes.toString, "function"); + +}, "setting an attribute should not overwrite the methods defined by prototype ancestors of an `NamedNodeMap` object"); + +test(() => { + + const element = document.createElement("div"); + element.setAttributeNS("foo", "length", "first"); + + assert_equals(element.attributes.length, 1, "one attribute"); + +}, "setting an attribute should not overwrite the the length property of an `NamedNodeMap` object"); + +</script> diff --git a/dom/nodes/getElementsByClassName-32.html b/dom/nodes/getElementsByClassName-32.html new file mode 100644 index 0000000..29eb413 --- /dev/null +++ b/dom/nodes/getElementsByClassName-32.html
@@ -0,0 +1,68 @@ +<!DOCTYPE html> +<html> +<meta charset="utf-8"> +<title>Node.prototype.getElementsByClassName tests imported from jsdom</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div class="df-article" id="1"> +</div> +<div class="df-article" id="2"> +</div> +<div class="df-article" id="3"> +</div> + +<script> +"use strict"; + +test(() => { + + const p = document.createElement("p"); + p.className = "unknown"; + document.body.appendChild(p); + + const elements = document.getElementsByClassName("first-p"); + assert_array_equals(elements, []); + +}, "cannot find the class name"); + +test(() => { + + const p = document.createElement("p"); + p.className = "first-p"; + document.body.appendChild(p); + + const elements = document.getElementsByClassName("first-p"); + assert_array_equals(elements, [p]); + +}, "finds the class name"); + + +test(() => { + + const p = document.createElement("p"); + p.className = "the-p second third"; + document.body.appendChild(p); + + const elements1 = document.getElementsByClassName("the-p"); + assert_array_equals(elements1, [p]); + + const elements2 = document.getElementsByClassName("second"); + assert_array_equals(elements2, [p]); + + const elements3 = document.getElementsByClassName("third"); + assert_array_equals(elements3, [p]); + +}, "finds the same element with multiple class names"); + +test(() => { + + const elements = document.getElementsByClassName("df-article"); + + assert_equals(elements.length, 3); + assert_array_equals(Array.prototype.map.call(elements, el => el.id), ["1", "2", "3"]); + +}, "does not get confused by numeric IDs"); + +</script> diff --git a/dom/nodes/getElementsByClassName-empty-set.html b/dom/nodes/getElementsByClassName-empty-set.html new file mode 100644 index 0000000..75b8d5a --- /dev/null +++ b/dom/nodes/getElementsByClassName-empty-set.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<meta charset="utf-8"> +<title>Node.prototype.getElementsByClassName with no real class names</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<span class=" ">test</span> + +<script> +"use strict"; + +test(() => { + const elements = document.getElementsByClassName(""); + assert_array_equals(elements, []); +}, "Passing an empty string to getElementsByClassName should return an empty HTMLCollection"); + +test(() => { + const elements = document.getElementsByClassName(" "); + assert_array_equals(elements, []); +}, "Passing a space to getElementsByClassName should return an empty HTMLCollection"); + +test(() => { + const elements = document.getElementsByClassName(" "); + assert_array_equals(elements, []); +}, "Passing three spaces to getElementsByClassName should return an empty HTMLCollection"); + +</script> diff --git a/dom/nodes/getElementsByClassName-whitespace-class-names.html b/dom/nodes/getElementsByClassName-whitespace-class-names.html new file mode 100644 index 0000000..59bfd2e --- /dev/null +++ b/dom/nodes/getElementsByClassName-whitespace-class-names.html
@@ -0,0 +1,50 @@ +<!DOCTYPE html> +<html> +<meta charset="utf-8"> +<title>Node.prototype.getElementsByClassName with no real class names</title> +<link rel=help href="https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<span class="">LINE TABULATION</span> +<span class="…">NEXT LINE</span> +<span class=" ">NO-BREAK SPACE</span> +<span class=" ">OGHAM SPACE MARK</span> +<span class=" ">EN QUAD</span> +<span class=" ">EM QUAD</span> +<span class=" ">EN SPACE</span> +<span class=" ">EM SPACE</span> +<span class=" ">THREE-PER-EM SPACE</span> +<span class=" ">FOUR-PER-EM SPACE</span> +<span class=" ">SIX-PER-EM SPACE</span> +<span class=" ">FIGURE SPACE</span> +<span class=" ">PUNCTUATION SPACE</span> +<span class=" ">THIN SPACE</span> +<span class=" ">HAIR SPACE</span> +<span class="
">LINE SEPARATOR</span> +<span class="
">PARAGRAPH SEPARATOR</span> +<span class=" ">NARROW NO-BREAK SPACE</span> +<span class=" ">MEDIUM MATHEMATICAL SPACE</span> +<span class=" ">IDEOGRAPHIC SPACE</span> + +<span class="᠎">MONGOLIAN VOWEL SEPARATOR</span> +<span class="​">ZERO WIDTH SPACE</span> +<span class="‌">ZERO WIDTH NON-JOINER</span> +<span class="‍">ZERO WIDTH JOINER</span> +<span class="⁠">WORD JOINER</span> +<span class="">ZERO WIDTH NON-BREAKING SPACE</span> + +<script> +"use strict"; + +const spans = document.querySelectorAll("span"); + +for (const span of spans) { + test(() => { + const className = span.getAttribute("class"); + assert_equals(className.length, 1, "Sanity check: the class name was retrieved and is a single character"); + const shouldBeSpan = document.getElementsByClassName(className); + assert_array_equals(shouldBeSpan, [span]); + }, `Passing a ${span.textContent} to getElementsByClassName still finds the span`); +} +</script> diff --git a/dom/nodes/svg-template-querySelector.html b/dom/nodes/svg-template-querySelector.html new file mode 100644 index 0000000..5d2f634 --- /dev/null +++ b/dom/nodes/svg-template-querySelector.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>querySelector on template fragments with SVG elements</title> + +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<template id="template1"><div></div></template> +<template id="template2"><svg></svg></template> +<template id="template3"><div><svg></svg></div></template> + +<script> +"use strict"; + +test(() => { + const fragment = document.querySelector("#template1").content; + assert_not_equals(fragment.querySelector("div"), null); +}, "querySelector works on template contents fragments with HTML elements (sanity check)"); + +test(() => { + const fragment = document.querySelector("#template2").content; + assert_not_equals(fragment.querySelector("svg"), null); +}, "querySelector works on template contents fragments with SVG elements"); + +test(() => { + const fragment = document.querySelector("#template3").content; + assert_not_equals(fragment.firstChild.querySelector("svg"), null); +}, "querySelector works on template contents fragments with nested SVG elements"); +</script> diff --git a/dom/window-extends-event-target.html b/dom/window-extends-event-target.html new file mode 100644 index 0000000..3b69032 --- /dev/null +++ b/dom/window-extends-event-target.html
@@ -0,0 +1,55 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Window extends EventTarget</title> +<link rel="help" href="https://github.com/jsdom/jsdom/issues/2830"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<body> +<script> +"use strict"; + +test(() => { + + assert_equals(window.addEventListener, EventTarget.prototype.addEventListener); + assert_equals(window.removeEventListener, EventTarget.prototype.removeEventListener); + assert_equals(window.dispatchEvent, EventTarget.prototype.dispatchEvent); + +}, "EventTarget methods on Window instances are inherited from the EventTarget prototype"); + +test(() => { + + const kCustom = "custom-event"; + const customEvent = new CustomEvent(kCustom, { + bubbles: true + }); + + let target; + window.addEventListener.call(document.body, kCustom, function () { + target = this; + }); + + document.body.dispatchEvent(customEvent); + + assert_equals(target, document.body); + +}, "window.addEventListener respects custom `this`"); + +test(() => { + + const kCustom = "custom-event"; + const customEvent = new CustomEvent(kCustom, { + bubbles: true + }); + + let target; + window.addEventListener.call(null, kCustom, function () { + target = this; + }); + + document.body.dispatchEvent(customEvent); + + assert_equals(target, window); + +}, "window.addEventListener treats nullish `this` as `window`"); +</script>